package top.v5it.japi.plus.common.util;

import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import top.v5it.japi.plus.common.func.FuncTemplate;

import java.io.File;
import java.lang.reflect.Method;
import java.util.function.Supplier;

/**
 * 根据IP地址获取城市
 *
 * @author zhanpu
 * @date 2019/6/12
 */
@Slf4j
public class AddressUtil {

    /**
     * 设置ip数据库目录的系统环境参数名，按JVM参数格式设置-Dip2region.dir=/var/jsapi/ip2region
     */
    private static final String IP2REGION_DIR_KEY = "ip2region.dir";

    /**
     * 默认ip数据库存储路径
     */
    private static final String DEFAULT_IP2REGION_RESOURCE_DIR = "/var/japi/ip2region";

    /**
     * 获取数据库存储路径
     */
    private final static Supplier<String> SUPPLIER_LOG_PATH = () -> System.getProperty(IP2REGION_DIR_KEY, DEFAULT_IP2REGION_RESOURCE_DIR) + "/ip2region.db";

    private AddressUtil() {
        throw new UnsupportedOperationException();
    }

    /**
     * 根据ip获取城市信息
     *
     * @param ip ip地址
     * @return 城市信息
     */
    public static String getCityInfo(String ip) {
        String dbPath = SUPPLIER_LOG_PATH.get();
        //本地测试使用地址
        File file = new File(dbPath);

        return (String) FuncTemplate
                .ifElseFunc2(file.exists() && Util.isIpAddress(ip))
                .applyWithFuncException(
                        () -> {
                            DbConfig config = new DbConfig();
                            @Cleanup
                            DbSearcher searcher = new DbSearcher(config, file.getPath());
                            Method method = searcher.getClass().getMethod("btreeSearch", String.class);
                            DataBlock dataBlock = (DataBlock) method.invoke(searcher, ip);
                            return dataBlock.getRegion();
                        },
                        () -> {
                            log.error("+++++Error: Invalid ip address or {} not exists", dbPath);
                            return "XX XX";
                        });
    }

}
